home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cubase Magazine 32
/
Issue #32.iso
/
3-TUTORIAL
/
TRIANTI
/
convoluzione
/
loadwave.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-02-18
|
6KB
|
226 lines
/*
Lettore di file wave
(C)2000 - 2001 Aldo Trianti
*/
#include <stdio.h>
#include <stdlib.h>
#include "wavereader.h"
static int TrovaChunk (FILE* file, ChunkInfo* parentChunk, ChunkInfo* info, unsigned long tipo_chunk);
static void s2f (short* int_buffer, float* float_buffer, unsigned int numeroCampioni);
WaveFileDirect* WFD_ApriWave (char *nome_file)
{
int retCode;
RiffChunk ckRiff;
ChunkInfo ckFormat;
WaveFormat wf;
ChunkInfo ckData;
unsigned long tipo_file; /* RIFF */
WaveFileDirect* pWaveFile = NULL;
FILE* file = NULL;
file = fopen (nome_file, "rb"); /* apre il file in lettura */
if (file == NULL) goto error;
/* legge il chunk iniziale */
retCode = fread(&ckRiff, sizeof(RiffChunk), 1, file);
if (retCode != 1) goto error;
/* Procede solo se il file Φ di tipo RIFF */
if (ckRiff.id != RIFF_CHUNK) goto error;
/* ed il tipo di dati deve essere WAVE */
retCode = fread (&tipo_file, sizeof(unsigned long), 1, file);
if (retCode != 1) goto error;
if (tipo_file != TYPE_WAVE) goto error;
/* ora troviamo il chunk che descrive il formato del file wave (numero di
canali, bit e frequenza di campionamento */
retCode = TrovaChunk (file, &ckRiff, &ckFormat, FMT__CHUNK);
if (retCode != 1) goto error;
/* leggiamo il formato del file wave */
retCode = fread (&wf, sizeof wf, 1, file);
if (retCode != 1) goto error;
/* controllo formato file */
if (wf.wFormatTag != 1) /* campioni interi */
goto error; /* non supportiamo altri formati... */
if (wf.wBitsPerSample != 16) /* solo file a 16 bit */
goto error;
if (wf.nChannels > 2) /* mono o stereo. altri formati non supportati */
goto error;
/* passiamo ora al chunk che contiene i dati */
retCode = TrovaChunk (file, &ckRiff, &ckData, DATA_CHUNK);
if (retCode != 1) goto error;
pWaveFile = malloc(sizeof(WaveFileDirect));
pWaveFile->file = file;
pWaveFile->nChannels = wf.nChannels;
pWaveFile->sampleRate = wf.nSamplesPerSec;
pWaveFile->bitPerSample = wf.wBitsPerSample;
pWaveFile->cbBlockAlign = wf.nBlockAlign;
pWaveFile->nSamples = ckData.chunk.cbSize / wf.nBlockAlign;
pWaveFile->nSamplePosition = 0;
pWaveFile->pcmDataOffset = ftell(file);
return pWaveFile;
error:
if (NULL != file) fclose(file);
if (NULL != pWaveFile) free(pWaveFile);
return NULL; /* oops... non abbiamo trovato il chunk,
o qualcosa Φ andato storto. */
}
int WFD_Chiudi(WaveFileDirect *wfd)
{
if (NULL != wfd->file) fclose(wfd->file);
if (NULL != wfd) free(wfd);
return 1;
}
int WFD_Posiziona (WaveFileDirect *wfd, int numeroCampione)
{
if (numeroCampione >= 0 && numeroCampione < wfd->nSamples)
wfd->nSamplePosition = numeroCampione;
return wfd->nSamplePosition;
}
int WFD_Leggi (WaveFileDirect *wfd, float *buffer, int numeroCampioni)
{
int check;
int disk_offset = wfd->pcmDataOffset +
wfd->nSamplePosition * wfd->cbBlockAlign;
check = fseek (wfd->file, disk_offset, SEEK_SET);
if (check == 0) /* Ok! */
{
short temp[1024]; /* legge 1024 campioni alla volta dal file */
int campioniTotaliDaLeggere = numeroCampioni * wfd->nChannels;
float scala = 1.0F/32768.0F;
check = 0;
while (campioniTotaliDaLeggere != 0)
{
int k;
/* legge 1024 (o meno) campioni alla volta */
int daLeggere = campioniTotaliDaLeggere;
if (daLeggere > 1024) daLeggere = 1024;
fread(temp, sizeof(short), daLeggere, wfd->file);
/* converte da intero a float */
for (k = 0; k < daLeggere; ++k)
buffer[k] = temp[k] * scala;
buffer += daLeggere;
check += daLeggere;
campioniTotaliDaLeggere -= daLeggere;
}
}
else
check = 0;
return check;
}
int WFD_LeggiCampione(WaveFileDirect *wfd, float* buffer)
{
static float scale = 1.0F / 32768.0F;
int ok = 0;
if (wfd->nChannels == 1)
{
short temp;
if (fread(&temp, 2, 1, wfd->file) != 0)
{
*buffer = temp * scale;
ok = 1;
}
}
else
{
short temp[2];
if (fread(&temp, 1, 4, wfd->file) == 4)
{
buffer[0] = temp[0] * scale;
buffer[1] = temp[1] * scale;
ok = 1;
}
}
return ok;
}
/*-------------------------------------------------------------------------*/
static int TrovaChunk (FILE* file,
ChunkInfo* parentChunk,
ChunkInfo* info,
unsigned long tipo_chunk)
{
long retCode;
unsigned long dimensioneChunk;
/* dimensione, in byte dei dati contenuti nel chunk */
unsigned long byteRimanenti = parentChunk->chunk.cbSize;
/* posiziona il file esattamente alla fine del descrittore
del chunk */
if (parentChunk->chunk.id == RIFF_CHUNK)
retCode = fseek(file, 12, SEEK_SET);
else
retCode = fseek(file, parentChunk->offset, SEEK_SET);
if (retCode) goto error;
while (byteRimanenti > 0)
{
/* legge il descrittore del chunk */
retCode = fread (&(info->chunk), sizeof(RiffChunk), 1, file);
if (retCode != 1) goto error;
/* controlla se Φ del tipo specificato... */
if (info->chunk.id == tipo_chunk)
{
info->offset = ftell(file); /* trovato! */
return 1;
}
/* calcola la dimensione del chunk */
dimensioneChunk = info->chunk.cbSize;
/* i numeri di byte devono essere sempre pari.
Se non lo sono aggiungiamo 1 alla dimensione del
chunk. */
if (dimensioneChunk & 1) ++dimensioneChunk;
/* aggiorna i byte rimanenti */
byteRimanenti -= dimensioneChunk + sizeof(RiffChunk);
/* avanza nel file saltando i dati presenti nel chunk */
retCode = fseek (file, dimensioneChunk, SEEK_CUR);
if (retCode) goto error;
/* ora, essendo il puntatore del file posizionato all'inizio
del prossimo chunk, possiamo ripetere l'operazione... */
}
error:
return 0; /* oops... non abbiamo trovato il chunk,
o qualcosa Φ andato storto. */
}